package ged.customizationCode.shapes.connections;

import java.awt.geom.CubicCurve2D;
import java.awt.geom.PathIterator;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.PolylineConnection;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.PrecisionPoint;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Path;
import org.eclipse.swt.widgets.Display;

/**
 * 
 * @author scheglov_ke
 * http://www.eclipse.org/forums/index.php/t/269054/
 */

public class PipeConnection extends PolylineConnection {

        private static int OFFSET_X = 80;
        private static int OFFSET_Y = 15;

        private List<PrecisionPoint> connectionPoints = new ArrayList<PrecisionPoint>();

        private int bend_X;
        private int bend_Y;

        private int queueEntries = 0;

        @Override
        protected void outlineShape(Graphics g) {

                connectionPoints.clear();
                Point bendPointStart = null;
                Point bendPointEnd = null;
                int lineup = calculateLineup(getStart(), getEnd());
                switch (lineup) {
                case 1:
                        bendPointStart = new Point(getStart().x + bend_X, getStart().y
                                        - bend_Y);
                        bendPointEnd = new Point(getEnd().x - bend_X, getEnd().y + bend_Y);

                        break;

                case 2:
                        bendPointStart = new Point(getStart().x + bend_X, getStart().y
                                        + bend_Y);
                        bendPointEnd = new Point(getEnd().x - bend_X, getEnd().y - bend_Y);

                        break;

                case 3:
                        bendPointStart = new Point(getStart().x + bend_X, getStart().y
                                        - bend_Y);
                        bendPointEnd = new Point(getEnd().x - bend_X, getEnd().y + bend_Y);

                        break;

                case 4:
                        bendPointStart = new Point(getStart().x + bend_X, getStart().y
                                        + bend_Y);
                        bendPointEnd = new Point(getEnd().x - bend_X, getEnd().y - bend_Y);

                        break;
                default:
                        break;
                }

                CubicCurve2D curve = new CubicCurve2D.Float(getStart().x, getStart().y,
                                bendPointStart.x, bendPointStart.y, bendPointEnd.x,
                                bendPointEnd.y, getEnd().x, getEnd().y);

                PathIterator pi = curve.getPathIterator(null, Float.MIN_VALUE);

                while (pi.isDone() == false) {
                        PrecisionPoint p = getCurrentPoint(pi);
                        connectionPoints.add(p);

                        pi.next();
                }

                Path p = new Path(Display.getCurrent());
                p.moveTo(getStart().x, getStart().y);

                for (PrecisionPoint po : connectionPoints) {
                        p.lineTo((float) po.preciseX(), (float) po.preciseY());
                }
                p.lineTo(getEnd().x, getEnd().y);

                g.setInterpolation(SWT.HIGH);

                Display display = Display.getCurrent();
                g.setAntialias(SWT.ON);
                g.setForegroundColor(display.getSystemColor(SWT.COLOR_DARK_BLUE));
                g.setLineWidth(4);
                g.setAlpha(180);

                g.drawPath(p);
                g.setForegroundColor(display.getSystemColor(SWT.COLOR_WHITE));
                g.setLineWidth(2);
                g.drawPath(p);

                g.setForegroundColor(display.getSystemColor(SWT.COLOR_RED));
                g.setLineWidth(4);
                int counter = queueEntries;
                Path path = new Path(Display.getCurrent());

                PrecisionPoint last = connectionPoints.get(connectionPoints.size() - 1);
                path.moveTo((float) last.preciseX(), (float) last.preciseY());
                int size = connectionPoints.size() - 1;
                for (int i = 0; i < counter * 35; i++) {
                        PrecisionPoint nextPoint = connectionPoints.get(size - i);
                        path.lineTo((float) nextPoint.preciseX(),
                                        (float) nextPoint.preciseY());
                }
                if (counter > 1) {
                        g.drawPath(path);
                }
        }

        @Override
        public void paint(Graphics graphics) {
                // TODO Auto-generated method stub

                super.paint(graphics);
        }

        private PrecisionPoint getCurrentPoint(PathIterator pi) {
                double[] coordinates = new double[6];
                PrecisionPoint p = new PrecisionPoint();

                int type = pi.currentSegment(coordinates);
                if (type == PathIterator.SEG_LINETO || type == PathIterator.SEG_MOVETO) {

                        double x = coordinates[0];

                        double y = coordinates[1];

                        p.setPreciseX(x);

                        p.setPreciseY(y);

                }
                return p;
        }

        @Override
        public Rectangle getBounds() {
                // TODO Auto-generated method stub
                Rectangle bounds = super.getBounds();

                Rectangle newBounds = new Rectangle();
                newBounds.width = bounds.width + 400;
                newBounds.height = bounds.height + 400;
                newBounds.x = bounds.x - 200;
                newBounds.y = bounds.y - 200;
                bounds.union(newBounds);
                return bounds;
        }

        private int calculateLineup(Point startPoint, Point endPoint) {
                if (startPoint.x <= endPoint.x && startPoint.y <= endPoint.y) {
                        this.bend_X = OFFSET_X;
                        this.bend_Y = OFFSET_Y;
                        return 1;
                }
                if (startPoint.x <= endPoint.x && startPoint.y >= endPoint.y) {
                        this.bend_X = OFFSET_X;
                        this.bend_Y = OFFSET_Y;
                        return 2;
                }
                if (startPoint.x >= endPoint.x && startPoint.y >= endPoint.y) {
                        int reference = (startPoint.x - endPoint.x);
                        if (reference > 100)
                                reference = 100;
                        this.bend_X = OFFSET_X + reference;
                        this.bend_Y = OFFSET_Y + 30;
                        return 3;
                }
                if (startPoint.x >= endPoint.x && startPoint.y <= endPoint.y) {
                        int reference = (startPoint.x - endPoint.x) / 2;
                        if (reference > 130)
                                reference = 130;
                        this.bend_X = OFFSET_X + reference;
                        this.bend_Y = OFFSET_Y + 30;
                        return 4;
                }

                return 0;
        }

        public List<PrecisionPoint> getconnectionPoints() {
                return connectionPoints;
        }

        public void setconnectionPoints(List<PrecisionPoint> connectionPoints) {
                this.connectionPoints = connectionPoints;
        }

        public void setEntry(int count) {
                this.queueEntries = count;
        }

}